/******************************************************************************

  Copyright (C), 2011-2014, Hisilicon Tech. Co., Ltd.

******************************************************************************
  File Name             :   avplay_frc.c
  Version               :   Initial Draft
  Author                :   Hisilicon multimedia software group
  Created               :
  Description           :   Algorithm Module
  History               :
  1.Date                :
  Author                :
  Modification          :   Created file

******************************************************************************/

#include <string.h>
#include <sys/time.h>
#include <sys/times.h>
#include <pthread.h>

#include "avplay_frc.h"

#ifdef __cplusplus
 #if __cplusplus
extern "C" {
 #endif
#endif /* End of #ifdef __cplusplus */

HI_VOID AVPLAY_FrcCreate(AVPLAY_ALG_FRC_S *FrcCalAlg, AVPLAY_FRC_CFG_S *FrcParamCfg, AVPLAY_FRC_CTRL_S *FrcCtrlInfo)
{
    memset(FrcCalAlg, 0, sizeof(AVPLAY_ALG_FRC_S));

    FrcCtrlInfo->s32FrmState = 0;

    FrcParamCfg->u32InRate      = 25;
    FrcParamCfg->u32OutRate     = 25;
    FrcParamCfg->u32PlayRate    = AVPLAY_ALG_FRC_BASE_PLAY_RATIO;
}

HI_VOID AVPLAY_FrcDestroy(AVPLAY_ALG_FRC_S *FrcCalAlg)
{
    memset(FrcCalAlg, 0, sizeof(AVPLAY_ALG_FRC_S));
}

HI_VOID AVPLAY_FrcReset(AVPLAY_ALG_FRC_S *hFrc)
{
    memset(hFrc, 0, sizeof(AVPLAY_ALG_FRC_S));
}

HI_VOID AVPLAY_FrcCalculate(AVPLAY_ALG_FRC_S *hFrc, AVPLAY_FRC_CFG_S *pstFrcCfg, AVPLAY_FRC_CTRL_S *pstFrcCtrl)
{
    HI_U32  quot, remder, u32InRate, u32OutRate, u32tmpFrameRate;
    HI_S32  flag = 0;
    HI_U64  tmp = 0;
    HI_U64  remder_cyc;
    HI_U32  u32PlayRate;
    HI_U32  u32CurID;     /* current insert or drop position in a FRC cycle, add by sdk*/

    u32tmpFrameRate = pstFrcCfg->u32InRate;

    //if (u32tmpFrameRate <= 60)    /* to support stream which rate is less tha 6 frame per second/ */
    if (u32tmpFrameRate < 1)
    {
        pstFrcCtrl->s32FrmState = 0;
        return;
    }

    if ( (hFrc->u32OutRate != pstFrcCfg->u32OutRate)
        ||(hFrc->u32PlayRate != pstFrcCfg->u32PlayRate)         /*add by sdk*/
        ||(hFrc->u32InRate != u32tmpFrameRate)
        )
    {
        //RESET
        AVPLAY_FrcReset(hFrc);
        hFrc->u32InRate = u32tmpFrameRate;
        hFrc->u32OutRate = pstFrcCfg->u32OutRate;
        hFrc->u32PlayRate = pstFrcCfg->u32PlayRate;
        hFrc->u32CurID = 1;     /*this should be 0 or 1 ?*/
    }

    u32PlayRate = pstFrcCfg->u32PlayRate; //8bit fraction

    u32OutRate = (hFrc->u32OutRate) * AVPLAY_ALG_FRC_PRECISION * AVPLAY_ALG_FRC_BASE_PLAY_RATIO / u32PlayRate;  //support  256X playrate
    u32InRate = (hFrc->u32InRate) * AVPLAY_ALG_FRC_PRECISION;

    u32CurID = hFrc->u32CurID;

    if ((u32InRate) < (u32OutRate))  ////Lower framerate to Higher framerate ---need repeat
    {
        quot = (u32OutRate)/(u32InRate);
        remder = (u32OutRate)%(u32InRate);
        remder_cyc = (HI_U64)(hFrc->u32InputCount%u32InRate + 1);

        if (remder == 0)
        {
            flag = 0;
        }
        else
        {
            tmp = (HI_U64)(((HI_U64)u32InRate * (HI_U64)u32CurID + remder / 2) / remder);
            if (tmp == remder_cyc)
            {
                flag = 1;
                hFrc->u32CurID++;
                hFrc->u32CurID = (hFrc->u32CurID%remder == 0) ? remder: (hFrc->u32CurID % remder);
            }
            else
            {
                flag = 0;
            }
        }

        if (flag == 1)
        {
            //repeat time: (quot-1)+1;
            pstFrcCtrl->s32FrmState = quot;
        }
        else
        {
            //repeat time: (quot-1);
            pstFrcCtrl->s32FrmState = quot - 1;
        }

    }
    else if (u32InRate > u32OutRate) //Higher framerate to Lower framerate ---need drop
    {
        remder = (u32InRate)-(u32OutRate);
        remder_cyc = (HI_U64)(hFrc->u32InputCount%u32InRate + 1);

        if (remder == 0)
        {
            flag = 0;
        }
        else
        {
            tmp = (HI_U64)(((HI_U64)u32InRate * (HI_U64)u32CurID + remder / 2) / remder);
            if (tmp == remder_cyc)
            {
                flag = 1;
                hFrc->u32CurID++;
                hFrc->u32CurID = (hFrc->u32CurID % remder == 0) ? remder: (hFrc->u32CurID % remder);
            }
            else
            {
                flag = 0;
            }
        }

        //if flag==1, need drop this frame.
        if (flag == 1)
        {
            pstFrcCtrl->s32FrmState = -1;
        }
        else
        {
            pstFrcCtrl->s32FrmState = 0;
        }
    }
    else  //don't need frame rate conversion
    {
        pstFrcCtrl->s32FrmState = 0;
    }

    hFrc->u32InputCount++;

    return;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */


